package bgate.connector;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

import java.util.Vector;

import android.util.Log;

public class MasterConnector  {

    private String _masterHost = "";
    private int _masterPort = 0;
    private Socket _socket;
    private DataInputStream _inFromMaster;
    private PrintStream _outToMaster;    
    private boolean _going = false;
    private DataTransfer _midlet;
    private Vector _outQueue;
    private static final String TAG="MasterConnector";
    SlaveInfo info;

    public Socket getSocket() {
        return _socket;
    }

    public void setSocket(Socket _socket) {
        this._socket = _socket;
    }
    

    public MasterConnector(String address, int port, DataTransfer midlet, Vector outQueue) {
        _masterHost = address;
        _masterPort = port;
        _midlet = midlet;
        _outQueue = outQueue;        
        //info = new SlaveInfo(1, "125.214.19.90", 9000);
        info = new SlaveInfo(1, _masterHost, _masterPort);
    }
    private Socket createNewSocket(String host,int port)
    {

    	// Create a socket with a timeout
    	try {
    	    InetAddress addr = InetAddress.getByName(host);
    	  
    	    SocketAddress sockaddr = new InetSocketAddress(addr, port);

    	   
    	    Socket sock = new Socket();
    	    int timeoutMs = 2000;   // 2 seconds
    	    sock.connect(sockaddr, 2000);
    	    Log.d(TAG, "created socket");
    	    return sock;
    	} catch (UnknownHostException e) {
    		Log.d(TAG, e.toString());
    		return null;
    	} catch (SocketTimeoutException e) {
    		Log.d(TAG, e.toString());
    		return null;
    	} catch (IOException e) {
    		Log.d(TAG, e.toString());
    		return null;
    	}
    }

    public boolean getSlaveServer() throws IOException {

		try {
			Log.d(TAG, "get slave");

			Log.d(TAG, "get slave " + _masterHost);
			Log.d(TAG, "get slave " + _masterPort);
			// \\String url = "socket://" + _masterHost + ":" + _masterPort;
		
			_socket=createNewSocket(_masterHost,_masterPort);	
			if(_socket==null)
			{
				return false;
			}

			// _socket=createNewSocket(_masterHost,_masterPort);

			_inFromMaster = new DataInputStream(_socket.getInputStream());
			_outToMaster = new PrintStream(_socket.getOutputStream());

			String msg = "GETSLAVE:s";

			byte[] outMsg = null;

			int i;
			try {
				outMsg = new byte[msg.getBytes("UTF-8").length + 2];

				for (i = 0; i < msg.getBytes("UTF-8").length; i++) {
					outMsg[i] = msg.getBytes("UTF-8")[i];
				}
				outMsg[outMsg.length - 2] = (byte) 13;
				outMsg[outMsg.length - 1] = (byte) 10;
			} catch (UnsupportedEncodingException ex) {
				// ex.printStackTrace();
				Log.d(TAG, ex.toString());
				stopConn2Master();
				return false;
			}

			if (outMsg != null) {
				try {
					_outToMaster.write(outMsg);
					_outToMaster.flush();
				} catch (IOException ex) {
					// ex.printStackTrace();
					stopConn2Master();
					return false;
				}
			}

			Log.d(TAG, "read data from server");
			boolean running = true;
			byte[] buff = null;
			int buffLength;
			int bs, timeout = 0;
			StringBuffer sb = null;

			while (running) {
				Thread.sleep(10);
			//	Log.d(TAG, "reading.... ");
				while (_inFromMaster.available() > 0) {
				
					bs = _inFromMaster.available(); // get the amount of
													// characters waiting in the
													// buffer
					buff = new byte[bs];
					buffLength = buff.length;
					_inFromMaster.read(buff, 0, buffLength);
					sb = new StringBuffer();
					Log.d(TAG, "waiting info " + buff.length);
					for (i = 0; i < buff.length; i++) {
						if (buff[i] != 0 && buff[i] != 3) {
							sb.append((char) buff[i]);
						}
					}
					running = false;

				}
				timeout++;
				if (timeout > 12000) {
					running = false;
				}
				//Log.d(TAG, "running get slave");
			}
			Log.d(TAG, "get slave finish");

			String r = "";
			if (sb != null) {
				r = sb.toString();
				sb.delete(0, sb.capacity());
				sb = null;
			}

			if (r == null || r.trim().length() == 0) {
				stopConn2Master();
				return false;
			}
			if (r.startsWith("REPORT")) {
				info = (SlaveInfo) process(r, null);
				String ok = "HGOTS";
				_outToMaster.println(ok);
				stopConn2Master();
				ok = null;

			}

			r = null;
			_inFromMaster = null;
			_outToMaster = null;
			_socket = null;
		} catch (Exception e) {
			Log.d(TAG, "error " + e.toString());
			stopConn2Master();
			return false;
		}

		return true;
	}
   

    public Object process(String message, Object session) {
        
        System.out.println(message);
        int idx = message.indexOf(":");
        String tmp = message.substring(idx + 1);
        String[] content = tmp.split(",");

        int id = Integer.parseInt(content[0]);
        String address = content[1];
        int port = Integer.parseInt(content[2].trim());

        SlaveInfo info = new SlaveInfo(id, address, port);
        return info;
    }    

    public ClientConnector startConn2Slave(ClientConnector yomeClient) {
    	Log.d(TAG,"connect to slave "+info.address);
    	Log.d(TAG,"connect to slave " +info.port);
        yomeClient = new ClientConnector(info.address, info.port, _outQueue, _midlet);
        Runtime.getRuntime().gc();
        return yomeClient;
    }

    public void stopConn2Master() {
        if (_socket != null) {
            try {
                _socket.close();
                _socket = null;
                if (_outToMaster != null) {
                    _outToMaster.close();
                }
                if (_inFromMaster != null) {
                    _inFromMaster.close();
                }
            } catch (IOException ex) {
            }
        }
        Runtime.getRuntime().gc();
    }
}

class SlaveInfo {

    public int id = 0;
    public String address;
    public int port;

    public SlaveInfo(int id, String address, int port) {
        this.id = id;
        this.address = address;
        this.port = port;
    }    
}

